/*
* Copyright (C) 2020 ~ 2024 chaigec All Rights Reserved.
*
* Author:     chaigec <chaigec@163.com>
* Maintainer: chaigec <chaigec@163.com>

 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
*/

#include "MkRtpUtil.h"
#include "MkUtil/MkUtil.h"
#include "MkUtil/MkLog.h"

CMkRtcpPacket::CMkRtcpPacket()
    : m_Version(2)
    , m_Padding(0)
    , m_Count(0)
    , m_Payload(0)
    //, m_Length(0)
{

}

Uint32 CMkRtcpPacket::Parse(Uint8 * pBuf, Uint32 nLen, OUT Uint32 &nUsed)
{
    if (nLen < RtcpCommonLen) {
        return NotHasEnoughBuffer;
    }
    m_Version = (pBuf[0] >> 6) & 0x03;
    m_Padding = (pBuf[0] >> 5) & 0x01;
    m_Count = pBuf[0] & 0x0f;
    m_Payload = pBuf[1];
    Uint32 nPacketLen = (pBuf[2] << 8) | pBuf[3]; //The length of this RTCP packet in 32-bit words minus one, including the header and any padding.
    if (nPacketLen * 4 + RtcpCommonLen > nLen) {
        return NotHasEnoughBuffer;
    }
    nUsed = nPacketLen * 4 + RtcpCommonLen;
    Uint32 ErrorCode = NoneError;
    Uint32 nCurUsed = 0;
    switch (m_Payload) {
    case MkRtcpSr:
        ErrorCode = ParseSenderReport(pBuf + RtcpCommonLen, nPacketLen * 4, nCurUsed);
        break;
    case MkRtcpRr:
        ErrorCode = ParseReceptionReport(pBuf + RtcpCommonLen, nPacketLen * 4, nCurUsed);
        break;
    case MkRtcpSdes:
        ErrorCode = ParseSourceDescription(pBuf + RtcpCommonLen, nPacketLen * 4, nCurUsed);
        break;
    case MkRtcpBye:
        ErrorCode = ParseBye(pBuf + RtcpCommonLen, nPacketLen * 4, nCurUsed);
        break;
    case MkRtcpApp:
        ErrorCode = ParseApp(pBuf + RtcpCommonLen, nPacketLen * 4, nCurUsed);
        break;
    default:
        MkWarningLog("recv un define rtcp packet:%d\n", m_Payload);
        ErrorCode = InvalidParams;
        break;
    }
    return ErrorCode;
}

Uint32 CMkRtcpPacket::ParseSenderReport(const Uint8* pBuf, Uint32 nLen, Uint32& nUsed)
{
    //ender report info 24  one block package has 24byte
    if (static_cast<Uint32>(RtcpSRlen + GetCount()*ReportBlockLen) > nLen) {
        return NotHasEnoughBuffer;
    }
    nUsed = static_cast<Uint32>(RtcpSRlen + GetCount()*ReportBlockLen);
    Uint32 Offset = 0;
    m_SenderReport.Ssrc = CMkUtil::Read32Bit(pBuf, Offset);
    m_SenderReport.NtpTimeStamp = CMkUtil::Read64Bit(pBuf, Offset);
    m_SenderReport.RtpTimeStamp = CMkUtil::Read32Bit(pBuf, Offset);
    m_SenderReport.SenderPacketCount = CMkUtil::Read32Bit(pBuf, Offset);
    m_SenderReport.SenderOctetCount = CMkUtil::Read32Bit(pBuf, Offset);

    for (Uint8 i = 0; i < GetCount(); i++) {
        MkRtcpReportBlock Block;
        Block.FirstSsrc = CMkUtil::Read32Bit(pBuf, Offset);
        Block.FractionLost = CMkUtil::Read8Bit(pBuf, Offset);
        Block.TotalLost = CMkUtil::Read24Bit(pBuf, Offset);
        Block.LastSeq = CMkUtil::Read32Bit(pBuf, Offset);
        Block.Jitter = CMkUtil::Read32Bit(pBuf, Offset);
        Block.Lsr = CMkUtil::Read32Bit(pBuf, Offset);
        Block.Dlsr = CMkUtil::Read32Bit(pBuf, Offset);
        m_SenderReport.VecBlock.push_back(Block);
    }
    return NoneError;
}

Uint32 CMkRtcpPacket::ParseReceptionReport(const Uint8* pBuf, Uint32 nLen, Uint32& nUsed)
{
    if (nLen < sizeof(Uint32) + GetCount() * ReportBlockLen) {
        return NotHasEnoughBuffer;
    }
    nUsed = sizeof(Uint32) + GetCount() * ReportBlockLen;
    Uint32 Offset = 0;
    m_ReceptionReport.Ssrc = CMkUtil::Read32Bit(pBuf, Offset);
    for (Uint8 i = 0; i < GetCount(); i++) {
        MkRtcpReportBlock Block;
        Block.FirstSsrc = CMkUtil::Read32Bit(pBuf, Offset);
        Block.FractionLost = CMkUtil::Read8Bit(pBuf, Offset);
        Block.TotalLost = CMkUtil::Read24Bit(pBuf, Offset);
        Block.LastSeq = CMkUtil::Read32Bit(pBuf, Offset);
        Block.Jitter = CMkUtil::Read32Bit(pBuf, Offset);
        Block.Lsr = CMkUtil::Read32Bit(pBuf, Offset);
        Block.Dlsr = CMkUtil::Read32Bit(pBuf, Offset);
        m_ReceptionReport.VecBlock.emplace_back(Block);
    }
    return NoneError;
}

Uint32 CMkRtcpPacket::ParseSourceDescription(const Uint8* pBuf, Uint32 nLen, Uint32& nUsed)
{
    if (nLen < sizeof(Uint32)) {
        return NotHasEnoughBuffer;
    }
    Uint32 Offset = 0;
    Uint32 DomainLen = 0;
    m_SourceDescription.Ssrc = CMkUtil::Read32Bit(pBuf, Offset);
    for (Uint8 i = 0; i < GetCount(); i++) {
        if (Offset + 2 < nLen) {
            return NotHasEnoughBuffer;
        }
        MkRtcpSourceDescItem Item;
        Item.DescType = (MkRtcpSdesType)CMkUtil::Read8Bit(pBuf, Offset);
        DomainLen = CMkUtil::Read8Bit(pBuf, Offset);
        if (Offset + DomainLen < nLen) {
            return NotHasEnoughBuffer;
        }
        Item.DomainName = MkString((Int8*)(pBuf + Offset), DomainLen);
        Offset += DomainLen + 1;  //and 1 end byte
        m_SourceDescription.MapDescChunk[Item.DescType] = Item;
    }
    nUsed = Offset;
    return NoneError;
}

Uint32 CMkRtcpPacket::ParseBye(const Uint8* pBuf, Uint32 nLen, Uint32& nUsed)
{
    if (nLen < GetCount() * sizeof(Uint32) + nUsed) {
        return NotHasEnoughBuffer;
    }
    Uint32 Offset = 0;
    for (Uint8 i = 0; i < GetCount(); i++) {
        m_Bye.VecSsrc.push_back(CMkUtil::Read32Bit(pBuf, Offset));
    }
    if (Offset + nUsed < nLen) {
        m_Bye.ReasonLen = CMkUtil::Read8Bit(pBuf, Offset);
        if (Offset + nUsed + m_Bye.ReasonLen <= nLen) {
            m_Bye.Reason = MkString((Int8*)(pBuf + Offset), m_Bye.ReasonLen);
        }
    }
    return NoneError;
}

Uint32 CMkRtcpPacket::ParseApp(const Uint8* pBuf, Uint32 nLen, Uint32& nUsed)
{
    if (nLen < 8) {
        return NotHasEnoughBuffer;
    }
    Uint32 Offset = 0;
    m_App.Ssrc = CMkUtil::Read32Bit(pBuf, Offset);
    m_App.Name = CMkUtil::Read32Bit(pBuf, Offset);
    Uint32 DataLen = nLen - Offset - nUsed;
    DataLen -= (DataLen % 4);
    m_App.AppDependentData = MkString((Int8*)(pBuf + Offset), DataLen);
    return NoneError;
}

Uint32 CMkRtcpPacket::Packet(Uint8* pData, Uint32 nLen, Uint32& nUsed) const
{
    if (nLen < RtcpCommonLen) {
        return NotHasEnoughBuffer;
    }
    pData[0] = (m_Version << 6) | (m_Padding << 5) | m_Count;
    pData[1] = m_Payload;
    nUsed = RtcpCommonLen;

    Uint32 ErrorCode = InvalidParams;
    switch (m_Payload) {
    case MkRtcpSr:
        ErrorCode = PacketSenderReport(pData, nLen, nUsed);
        break;
    case MkRtcpRr:
        ErrorCode = PacketReceptionReport(pData, nLen, nUsed);
        break;
    case MkRtcpSdes:
        ErrorCode = PacketSourceDescription(pData, nLen, nUsed);
        break;
    case MkRtcpBye:
        ErrorCode = PacketBye(pData, nLen, nUsed);
        break;
    case MkRtcpApp:
        ErrorCode = PacketApp(pData, nLen, nUsed);
        break;
    default:
        break;
    }
    Uint32 nPacketLength = ((nUsed + 3) / 4) - 1;
    pData[2] = (nPacketLength >> 8) & 0xFF;
    pData[3] = nPacketLength & 0xFF;
    nUsed = nPacketLength * 4 + RtcpCommonLen;
    return ErrorCode;
}

Uint32 CMkRtcpPacket::GetSsrc() const
{
    Uint32 Ssrc = 0;
    switch (m_Payload) {
    case MkRtcpSr:
        Ssrc = m_SenderReport.Ssrc;
        break;
    case MkRtcpRr:
        Ssrc = m_ReceptionReport.Ssrc;
        break;
    case MkRtcpSdes:
        Ssrc = m_SourceDescription.Ssrc;
        break;
    case MkRtcpBye:
        if (!m_Bye.VecSsrc.empty()) {
            Ssrc = *m_Bye.VecSsrc.begin();
        }
        break;
    case MkRtcpApp:
        Ssrc = m_App.Ssrc;
        break;
    default:
        break;
    }
    return Ssrc;
}

Uint32 CMkRtcpPacket::PacketSenderReport(Uint8* pBuf, Uint32 nLen, Uint32& nUsed) const
{
    Uint32 nNeedLen = RtcpSRlen + GetCount()*ReportBlockLen;
    if (nNeedLen + nUsed > nLen) {
        return NotHasEnoughBuffer;
    }
    Uint8 *pData = pBuf + nUsed;
    Uint32 Offset = 0;
    CMkUtil::Packet32Bit(pData, Offset, m_SenderReport.Ssrc);
    CMkUtil::Packet64Bit(pData, Offset, m_SenderReport.NtpTimeStamp);
    CMkUtil::Packet32Bit(pData, Offset, m_SenderReport.RtpTimeStamp);
    CMkUtil::Packet32Bit(pData, Offset, m_SenderReport.SenderPacketCount);
    CMkUtil::Packet32Bit(pData, Offset, m_SenderReport.SenderOctetCount);

    for (Uint8 i = 0; i < GetCount(); i++) {
        CMkUtil::Packet32Bit(pData, Offset, m_SenderReport.VecBlock[i].FirstSsrc);
        CMkUtil::Packet8Bit(pData, Offset, m_SenderReport.VecBlock[i].FractionLost);
        CMkUtil::Packet24Bit(pData, Offset, m_SenderReport.VecBlock[i].TotalLost);
        CMkUtil::Packet32Bit(pData, Offset, m_SenderReport.VecBlock[i].LastSeq);
        CMkUtil::Packet32Bit(pData, Offset, m_SenderReport.VecBlock[i].Jitter);
        CMkUtil::Packet32Bit(pData, Offset, m_SenderReport.VecBlock[i].Lsr);
        CMkUtil::Packet32Bit(pData, Offset, m_SenderReport.VecBlock[i].Dlsr);
    }
    nUsed += nNeedLen;
    return NoneError;
}

Uint32 CMkRtcpPacket::PacketReceptionReport(Uint8* pBuf, Uint32 nLen, Uint32& nUsed) const
{
    Uint32 nNeedLen = sizeof(Uint32) + GetCount() * ReportBlockLen;
    if (nNeedLen + nUsed > nLen) {
        return NotHasEnoughBuffer;
    }
    Uint32 Offset = 0;
    Uint8 *pData = pBuf + nUsed;
    CMkUtil::Packet32Bit(pData, Offset, m_ReceptionReport.Ssrc);
    for (Uint8 i = 0; i < GetCount(); i++) {
        CMkUtil::Packet32Bit(pData, Offset, m_ReceptionReport.VecBlock[i].FirstSsrc);
        CMkUtil::Packet8Bit(pData, Offset, m_ReceptionReport.VecBlock[i].FractionLost);
        CMkUtil::Packet24Bit(pData, Offset, m_ReceptionReport.VecBlock[i].TotalLost);
        CMkUtil::Packet32Bit(pData, Offset, m_ReceptionReport.VecBlock[i].LastSeq);
        CMkUtil::Packet32Bit(pData, Offset, m_ReceptionReport.VecBlock[i].Jitter);
        CMkUtil::Packet32Bit(pData, Offset, m_ReceptionReport.VecBlock[i].Lsr);
        CMkUtil::Packet32Bit(pData, Offset, m_ReceptionReport.VecBlock[i].Dlsr);
    }
    nUsed += nNeedLen;
    return NoneError;
}

void CMkRtcpPacket::SetSourceDescriptionAddChunk(const MkRtcpSdesType& DescType, const MkString& DomainName)
{
    MkRtcpSourceDescItem Item;
    Item.DescType = DescType;
    Item.DomainName = DomainName;
    m_SourceDescription.MapDescChunk[DescType] = Item;
    SetCount(static_cast<Uint8>(m_SourceDescription.MapDescChunk.size()));
}

Uint32 CMkRtcpPacket::PacketSourceDescription(Uint8* pBuf, Uint32 nLen, Uint32& nUsed) const
{
    Uint32 nNeedLen = sizeof(Uint32);
    MkMap<MkRtcpSdesType, MkRtcpSourceDescItem>::const_iterator it = m_SourceDescription.MapDescChunk.begin();
    for (; it != m_SourceDescription.MapDescChunk.end(); it++) {
        nNeedLen += sizeof(Uint8) * 2 + it->second.DomainName.size();
    }
    if (0 != (nNeedLen % 4)) {
        nNeedLen = (nNeedLen / 4 + 1) * 4;
    }
    if (nUsed + nNeedLen > nLen) {
        return NotHasEnoughBuffer;
    }
    Uint32 Offset = 0;
    Uint8 *pData = pBuf + nUsed;
    CMkUtil::Packet32Bit(pData, Offset, m_SourceDescription.Ssrc);
    it = m_SourceDescription.MapDescChunk.begin();
    for (; it != m_SourceDescription.MapDescChunk.end(); it++) {
        CMkUtil::Packet8Bit(pData, Offset, it->second.DescType);
        CMkUtil::Packet8Bit(pData, Offset, static_cast<Uint8>(it->second.DomainName.size()));
        memcpy(pData + Offset, it->second.DomainName.c_str(), it->second.DomainName.size());
        Offset += it->second.DomainName.size();
    }
    nUsed += nNeedLen;
    return NoneError;
}

Uint32 CMkRtcpPacket::PacketBye(Uint8* pBuf, Uint32 nLen, Uint32& nUsed) const
{
    Uint32 nNeedLen = GetCount() * sizeof(Uint32) + sizeof(Uint8) + m_Bye.ReasonLen;
    if (0 != (nNeedLen % 4)) {
        nNeedLen = (nNeedLen / 4 + 1) * 4;
    }
    if (nUsed + nNeedLen > nLen) {
        return NotHasEnoughBuffer;
    }
    Uint32 Offset = 0;
    Uint8 *pData = pBuf + nUsed;
    for (Uint8 i = 0; i < GetCount(); i++) {
        CMkUtil::Packet32Bit(pData, Offset, m_Bye.VecSsrc[i]);
    }
    if (0 != m_Bye.ReasonLen) {
        CMkUtil::Packet8Bit(pData, Offset, m_Bye.ReasonLen);
        memcpy(pData + Offset, m_Bye.Reason.c_str(), m_Bye.ReasonLen);
    }
    nUsed += nNeedLen;
    return NoneError;
}

//Uint32 CMkRtcpApp::SetSubType(Uint8 SubType)
//{
//    if (SubType > 0x1f) // 5bit
//    {
//        return InvalidParams;
//    }
//    SetCount(SubType);  //count is subtype
//    return NoneError;
//}

Uint32 CMkRtcpPacket::PacketApp(Uint8* pBuf, Uint32 nLen, Uint32& nUsed) const
{
    Uint32 nNeedLen = sizeof(Uint32) * 2 + m_App.DataLen;
    if (0 != (nNeedLen % 4)) {
        nNeedLen = (nNeedLen / 4 + 1) * 4;
    }
    if (nUsed + nNeedLen > nLen) {
        return NotHasEnoughBuffer;
    }
    Uint32 Offset = 0;
    Uint8 *pData = pBuf + nUsed;
    CMkUtil::Packet32Bit(pData, Offset, m_App.Ssrc);
    CMkUtil::Packet32Bit(pData, Offset, m_App.Name);
    memcpy(pData + Offset, m_App.AppDependentData.c_str(), m_App.DataLen);
    nUsed += nNeedLen;
    return NoneError;
}

CMkRtcpPacket::~CMkRtcpPacket()
{
}


#define MaxCsrcCount  0x0f    //4bit max is 0x0f
#define RtpHeaderLen  12
CMkRtpPacket::CMkRtpPacket()
    : m_Version(2)
    , m_Padding(0)
    , m_HasExtension(0)
    , m_CsrcCount(0)
    , m_bMaker(0)
    , m_PayloadType(0)
    , m_SequenceNumber(0)
    , m_TimeStamp(0)
    , m_Ssrc(0)
    , m_ExtensionId(0)
    , m_PlayloadData(nullptr)
    , m_nPlayloadDataLength(0)
    , m_pHeader(nullptr)
    , m_nHeaderLen(0)
{

}

Uint32 CMkRtpPacket::Parse(Uint8 *pData, Uint32 nLen)
{
    if (nLen < RtpHeaderLen) {
        return NotHasEnoughBuffer;
    }
    Uint8 *pBegin = pData;
    Uint8 *pEnd = pData + nLen;
    m_Version = (*pBegin) >> 6;
    m_Padding = ((*pBegin) >> 5) & 0x01;
    if (2 != m_Version) { //only support version2 
        return InvalidParams;
    }
    m_HasExtension = ((*pBegin) >> 4) & 0x01;
    m_CsrcCount = (*pBegin) & 0x0f;
    pBegin++;
    if (MkRtcpSr <= *pBegin && *pBegin <= MkRtcpApp) {
        //rtcp packet
        return InvalidParams;
    }
    m_bMaker = ((*pBegin) >> 7) & 0x01;
    m_PayloadType = (*pBegin) & 0x7f;

    pBegin++;
    m_SequenceNumber = ((*pBegin) << 8) | *(pBegin + 1);
    pBegin += sizeof(Uint16);
    m_TimeStamp = ((*pBegin) << 24) | (*(pBegin + 1) << 16) | (*(pBegin + 2) << 8) | *(pBegin + 3);
    pBegin += sizeof(Uint32);
    m_Ssrc = ((*pBegin) << 24) | (*(pBegin + 1) << 16) | (*(pBegin + 2) << 8) | *(pBegin + 3);
    pBegin += sizeof(Uint32);
    if (m_CsrcCount * sizeof(Uint32) + RtpHeaderLen > nLen) {
        return NotHasEnoughBuffer;
    }
    for (Uint8 i = 0; i < m_CsrcCount; i++) {
        m_vecCsrc.push_back(((*pBegin) << 24) | (*(pBegin + 1) << 16) | (*(pBegin + 2) << 8) | *(pBegin + 3));
        pBegin += 4;
    }
    if (m_HasExtension) {
        if (pBegin + sizeof(Uint16) > pEnd) {
            return NotHasEnoughBuffer;
        }
        m_ExtensionId = ((*pBegin) << 8) | (*pBegin + 1);
        pBegin += sizeof(Uint16);
        if (pBegin + sizeof(Uint16) > pEnd) {
            return NotHasEnoughBuffer;
        }
        Uint16 ExtensionSize = ((*pBegin) << 8) | (*pBegin + 1);
        pBegin += sizeof(Uint16);
        if (pBegin + ExtensionSize > pEnd) {
            return NotHasEnoughBuffer;
        }
        m_ExtensionContent = MkString((Int8*)pBegin, ExtensionSize);
        pBegin += ExtensionSize;
    }
    m_PlayloadData = pBegin;
    m_nPlayloadDataLength = nLen - (pBegin - pData);
    if (m_Padding) {
        Uint8 PadingCount = pData[nLen - 1];
        m_nPlayloadDataLength -= PadingCount;
    }
    m_pHeader = pData;
    m_nHeaderLen = pBegin - pData;
    return NoneError;
}

Uint32 CMkRtpPacket::PacketHeader(Uint8* pBuf, Uint32 nLen)
{
    Uint32 nUseCount = RtpHeaderLen; //rtp header size
    nUseCount += m_CsrcCount * sizeof(Uint32);
    if (m_HasExtension) {
        nUseCount += sizeof(m_ExtensionId) + sizeof(Uint16);  // 2byte id  2byte len
        nUseCount += m_ExtensionContent.size();         //2byte len max 0xFFFF
    }
    if (nUseCount > nLen) {
        return NotHasEnoughBuffer;
    }
    m_nHeaderLen = nUseCount;
    m_pHeader = pBuf;
    Uint8 *p = m_pHeader;
    *(p++) = (m_Version << 6) | (m_Padding << 5) | (m_HasExtension << 4) + m_CsrcCount;
    *(p++) = (m_bMaker << 7) | m_PayloadType;
    *(p++) = (m_SequenceNumber >> 8) & 0xFF;
    *(p++) = m_SequenceNumber & 0xFF;
    *(p++) = (m_TimeStamp >> 24) & 0xFF;
    *(p++) = (m_TimeStamp >> 16) & 0xFF;
    *(p++) = (m_TimeStamp >> 8) & 0xFF;
    *(p++) = m_TimeStamp & 0xFF;
    *(p++) = (m_Ssrc >> 24) & 0xFF;
    *(p++) = (m_Ssrc >> 16) & 0xFF;
    *(p++) = (m_Ssrc >> 8) & 0xFF;
    *(p++) = m_Ssrc & 0xFF;
    //end packet header
    Uint32 tmpCsrc;
    for (size_t i = 0; i < m_vecCsrc.size(); i++) {
        tmpCsrc = htonl(m_vecCsrc[i]);
        memcpy(p, &tmpCsrc, sizeof(Uint32));
        p += sizeof(Uint32);
    }
    if (m_HasExtension) {
        *(p++) = (m_ExtensionId >> 8) & 0xFF;
        *(p++) = m_ExtensionId & 0xFF;
        Uint16 ExtenLen = static_cast<Uint16>(m_ExtensionContent.size());
        *(p++) = (ExtenLen >> 8) & 0xFF;
        *(p++) = ExtenLen & 0xFF;
        memcpy(p, m_ExtensionContent.c_str(), ExtenLen);
    }
    return NoneError;
}

Uint32 CMkRtpPacket::AddCsrc(Uint32 Csrc)
{
    if (m_vecCsrc.size() >= MaxCsrcCount) {
        return QueueFull;
    }
    m_vecCsrc.push_back(Csrc);
    m_CsrcCount = static_cast<Uint8>(m_vecCsrc.size());
    return NoneError;
}

Uint32 CMkRtpPacket::SetCsrc(MkVector<Uint32>& VecCsrc)
{
    if (VecCsrc.size() > MaxCsrcCount) {
        return QueueFull;
    }
    m_vecCsrc = VecCsrc;
    m_CsrcCount = static_cast<Uint8>(m_vecCsrc.size());
    return NoneError;
}


void CMkRtpPacket::ClearPayload()
{
    m_PlayloadData = nullptr;
    m_nPlayloadDataLength = 0;
    m_PayloadBufferList.Clear();
}

CMkRtpPacket::~CMkRtpPacket()
{
}